//
//  ocsocket.m
//  FFmpeg_X264_Codec
//
//  Created by luwinglee on 16/1/8.
//  Copyright © 2016年 suntongmian@163.com. All rights reserved.
//

#import "ocsocket.h"
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>
#import <unistd.h>

ocsocket *pthis;

@implementation ocsocket
{
    CFSocketRef m_socket;
}

void TCPServerConnectCallBack(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
{
    if (data != NULL) {
             // 当socket为kCFSocketConnectCallBack时，失败时回调失败会返回一个错误代码指针，其他情况返回NULL
            NSLog(@"连接失败");
             return;
    }
    
    char buffer[1024];
    int  len = 0;
    while ((len=(int)recv(CFSocketGetNative(socket), buffer, sizeof(buffer), 0))>0)
    {
         NSLog(@"%@", [NSString stringWithUTF8String:buffer]);
    }
    
    [pthis.delegate recvDataCallBack:buffer andSize:len];
    
}

-(id)initWithIPaddr:(char *)ip andPort:(int) port andType:(int) netType
{
    self = [super init];
    if (self != nil) {
        pthis = self;
        //add my code
        CFSocketContext sockContext = {0, // 结构体的版本，必须为0
            (__bridge void *)(self),
            // 一个任意指针的数据，可以用在创建时CFSocket对象相关联。这个指针被传递给所有的上下文中定义的回调。
            NULL, // 一个定义在上面指针中的retain的回调， 可以为NULL
            NULL, NULL};
         m_socket = (kCFAllocatorDefault, // 为新对象分配内存，可以为nil
                               PF_INET, // 协议族，如果为0或者负数，则默认为PF_INET
                               SOCK_STREAM, // 套接字类型，如果协议族为PF_INET,则它会默认为SOCK_STREAM
                               IPPROTO_TCP, // 套接字协议，如果协议族是PF_INET且协议是0或者负数，它会默认为IPPROTO_TCP
                               kCFSocketConnectCallBack, // 触发回调函数的socket消息类型，具体见Callback Types
                               TCPServerConnectCallBack, // 上面情况下触发的回调函数
                               &sockContext // 一个持有CFSocket结构信息的对象，可以为nil
                               );
        
        if (m_socket != nil) {
            struct sockaddr_in addr4;   // IPV4
            memset(&addr4, 0, sizeof(addr4));
            addr4.sin_len = sizeof(addr4);
            addr4.sin_family = AF_INET;
            addr4.sin_port = htons(port);
            addr4.sin_addr.s_addr = inet_addr(ip);  // 把字符串的地址转换为机器可识别的网络地址
            
            // 把sockaddr_in结构体中的地址转换为Data
            CFDataRef address = CFDataCreate(kCFAllocatorDefault, (UInt8 *)&addr4, sizeof(addr4));
            CFSocketConnectToAddress(m_socket,  // 连接的socket
                                     address, // CFDataRef类型的包含上面socket的远程地址的对象
                                     -1       // 连接超时时间，如果为负，则不尝试连接，而是把连接放在后台进行，如果_socket消息类型为kCFSocketConnectCallBack，将会在连接成功或失败的时候在后台触发回调函数
                                     );
            CFRunLoopRef cRunRef = CFRunLoopGetCurrent();    // 获取当前线程的循环
            // 创建一个循环，但并没有真正加如到循环中，需要调用CFRunLoopAddSource
            CFRunLoopSourceRef sourceRef = CFSocketCreateRunLoopSource(kCFAllocatorDefault, m_socket, 0);
            CFRunLoopAddSource(cRunRef, // 运行循环
                               sourceRef,  // 增加的运行循环源, 它会被retain一次
                               kCFRunLoopCommonModes  // 增加的运行循环源的模式
                               );
            CFRelease(sourceRef);
        }
        return self;
    }
    else
        return nil;
}
    
-(void) deInit
{
    pthis = nil;
}

-(int)sendData:(char *)data andSize:(int) size
{
    return (int)send(CFSocketGetNative(m_socket), data, size, 0);
}


@end

